home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / Mail / RCS / aux.c,v < prev    next >
Encoding:
Text File  |  1990-02-09  |  12.2 KB  |  680 lines

  1. head     1.2;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    ; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.2
  10. date     90.02.08.17.51.14;  author jhh;  state Exp;
  11. branches ;
  12. next     1.1;
  13.  
  14. 1.1
  15. date     90.02.08.15.33.15;  author jhh;  state Exp;
  16. branches ;
  17. next     ;
  18.  
  19.  
  20. desc
  21. @@
  22.  
  23.  
  24. 1.2
  25. log
  26. @Ported to sprite (patched in changes from old version of mail
  27. @
  28. text
  29. @/*
  30.  * Copyright (c) 1980 Regents of the University of California.
  31.  * All rights reserved.
  32.  *
  33.  * Redistribution and use in source and binary forms are permitted
  34.  * provided that the above copyright notice and this paragraph are
  35.  * duplicated in all such forms and that any documentation,
  36.  * advertising materials, and other materials related to such
  37.  * distribution and use acknowledge that the software was developed
  38.  * by the University of California, Berkeley.  The name of the
  39.  * University may not be used to endorse or promote products derived
  40.  * from this software without specific prior written permission.
  41.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  42.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  43.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  44.  */
  45.  
  46. #ifndef lint
  47. static char sccsid[] = "@@(#)aux.c    5.16 (Berkeley) 12/23/88";
  48. #endif /* not lint */
  49.  
  50. #include "rcv.h"
  51. #include <sys/stat.h>
  52. #include <sys/time.h>
  53.  
  54. /*
  55.  * Mail -- a mail program
  56.  *
  57.  * Auxiliary functions.
  58.  */
  59.  
  60. /*
  61.  * Return a pointer to a dynamic copy of the argument.
  62.  */
  63. char *
  64. savestr(str)
  65.     char *str;
  66. {
  67.     char *new;
  68.     int size = strlen(str) + 1;
  69.  
  70.     if ((new = salloc(size)) != NOSTR)
  71.         bcopy(str, new, size);
  72.     return new;
  73. }
  74.  
  75. /*
  76.  * Announce a fatal error and die.
  77.  */
  78.  
  79. /*VARARGS1*/
  80. panic(fmt, a, b)
  81.     char *fmt;
  82. {
  83.     fprintf(stderr, "panic: ");
  84.     fprintf(stderr, fmt, a, b);
  85.     putc('\n', stderr);
  86.     exit(1);
  87. }
  88.  
  89. /*
  90.  * Touch the named message by setting its MTOUCH flag.
  91.  * Touched messages have the effect of not being sent
  92.  * back to the system mailbox on exit.
  93.  */
  94. touch(mp)
  95.     register struct message *mp;
  96. {
  97.  
  98.     mp->m_flag |= MTOUCH;
  99.     if ((mp->m_flag & MREAD) == 0)
  100.         mp->m_flag |= MREAD|MSTATUS;
  101. }
  102.  
  103. /*
  104.  * Test to see if the passed file name is a directory.
  105.  * Return true if it is.
  106.  */
  107. isdir(name)
  108.     char name[];
  109. {
  110.     struct stat sbuf;
  111.  
  112.     if (stat(name, &sbuf) < 0)
  113.         return(0);
  114.     return((sbuf.st_mode & S_IFMT) == S_IFDIR);
  115. }
  116.  
  117. /*
  118.  * Count the number of arguments in the given string raw list.
  119.  */
  120. argcount(argv)
  121.     char **argv;
  122. {
  123.     register char **ap;
  124.  
  125.     for (ap = argv; *ap++ != NOSTR;)
  126.         ;    
  127.     return ap - argv - 1;
  128. }
  129.  
  130. /*
  131.  * Return the desired header line from the passed message
  132.  * pointer (or NOSTR if the desired header field is not available).
  133.  */
  134. char *
  135. hfield(field, mp)
  136.     char field[];
  137.     struct message *mp;
  138. {
  139.     register FILE *ibuf;
  140.     char linebuf[LINESIZE];
  141.     register int lc;
  142.     register char *hfield;
  143.     char *colon;
  144.  
  145.     ibuf = setinput(mp);
  146.     if ((lc = mp->m_lines - 1) < 0)
  147.         return NOSTR;
  148.     if (readline(ibuf, linebuf, LINESIZE) < 0)
  149.         return NOSTR;
  150.     while (lc > 0) {
  151.         if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0)
  152.             return NOSTR;
  153.         if (hfield = ishfield(linebuf, colon, field))
  154.             return savestr(hfield);
  155.     }
  156.     return NOSTR;
  157. }
  158.  
  159. /*
  160.  * Return the next header field found in the given message.
  161.  * Return >= 0 if something found, < 0 elsewise.
  162.  * "colon" is set to point to the colon in the header.
  163.  * Must deal with \ continuations & other such fraud.
  164.  */
  165. gethfield(f, linebuf, rem, colon)
  166.     register FILE *f;
  167.     char linebuf[];
  168.     register int rem;
  169.     char **colon;
  170. {
  171.     char line2[LINESIZE];
  172.     register char *cp, *cp2;
  173.     register int c;
  174.  
  175.     for (;;) {
  176.         if (--rem < 0)
  177.             return -1;
  178.         if ((c = readline(f, linebuf, LINESIZE)) <= 0)
  179.             return -1;
  180.         for (cp = linebuf; isprint(*cp) && *cp != ' ' && *cp != ':';
  181.              cp++)
  182.             ;
  183.         if (*cp != ':' || cp == linebuf)
  184.             continue;
  185.         /*
  186.          * I guess we got a headline.
  187.          * Handle wraparounding
  188.          */
  189.         *colon = cp;
  190.         cp = linebuf + c;
  191.         for (;;) {
  192.             while (--cp >= linebuf && (*cp == ' ' || *cp == '\t'))
  193.                 ;
  194.             cp++;
  195.             if (rem <= 0)
  196.                 break;
  197.             ungetc(c = getc(f), f);
  198.             if (c != ' ' && c != '\t')
  199.                 break;
  200.             if ((c = readline(f, line2, LINESIZE)) < 0)
  201.                 break;
  202.             rem--;
  203.             for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++)
  204.                 ;
  205.             c -= cp2 - line2;
  206.             if (cp + c >= linebuf + LINESIZE - 2)
  207.                 break;
  208.             *cp++ = ' ';
  209.             bcopy(cp2, cp, c);
  210.             cp += c;
  211.         }
  212.         *cp = 0;
  213.         return rem;
  214.     }
  215.     /* NOTREACHED */
  216. }
  217.  
  218. /*
  219.  * Check whether the passed line is a header line of
  220.  * the desired breed.  Return the field body, or 0.
  221.  */
  222.  
  223. char*
  224. ishfield(linebuf, colon, field)
  225.     char linebuf[], field[];
  226.     char *colon;
  227. {
  228.     register char *cp = colon;
  229.  
  230.     *cp = 0;
  231.     if (strcasecmp(linebuf, field) != 0) {
  232.         *cp = ':';
  233.         return 0;
  234.     }
  235.     *cp = ':';
  236.     for (cp++; *cp == ' ' || *cp == '\t'; cp++)
  237.         ;
  238.     return cp;
  239. }
  240.  
  241. /*
  242.  * Copy a string, lowercasing it as we go.
  243.  */
  244. istrcpy(dest, src)
  245.     register char *dest, *src;
  246. {
  247.  
  248.     do {
  249.         if (isupper(*src))
  250.             *dest++ = tolower(*src);
  251.         else
  252.             *dest++ = *src;
  253.     } while (*src++ != 0);
  254. }
  255.  
  256. /*
  257.  * The following code deals with input stacking to do source
  258.  * commands.  All but the current file pointer are saved on
  259.  * the stack.
  260.  */
  261.  
  262. static    int    ssp;            /* Top of file stack */
  263. struct sstack {
  264.     FILE    *s_file;        /* File we were in. */
  265.     int    s_cond;            /* Saved state of conditionals */
  266.     int    s_loading;        /* Loading .mailrc, etc. */
  267. } sstack[NOFILE];
  268.  
  269. /*
  270.  * Pushdown current input file and switch to a new one.
  271.  * Set the global flag "sourcing" so that others will realize
  272.  * that they are no longer reading from a tty (in all probability).
  273.  */
  274. source(arglist)
  275.     char **arglist;
  276. {
  277.     FILE *fi;
  278.     char *cp;
  279.  
  280.     if ((cp = expand(*arglist)) == NOSTR)
  281.         return(1);
  282.     if ((fi = fopen(cp, "r")) == NULL) {
  283.         perror(cp);
  284.         return(1);
  285.     }
  286.     if (ssp >= NOFILE - 1) {
  287.         printf("Too much \"sourcing\" going on.\n");
  288.         fclose(fi);
  289.         return(1);
  290.     }
  291.     sstack[ssp].s_file = input;
  292.     sstack[ssp].s_cond = cond;
  293.     sstack[ssp].s_loading = loading;
  294.     ssp++;
  295.     loading = 0;
  296.     cond = CANY;
  297.     input = fi;
  298.     sourcing++;
  299.     return(0);
  300. }
  301.  
  302. /*
  303.  * Pop the current input back to the previous level.
  304.  * Update the "sourcing" flag as appropriate.
  305.  */
  306. unstack()
  307. {
  308.     if (ssp <= 0) {
  309.         printf("\"Source\" stack over-pop.\n");
  310.         sourcing = 0;
  311.         return(1);
  312.     }
  313.     fclose(input);
  314.     if (cond != CANY)
  315.         printf("Unmatched \"if\"\n");
  316.     ssp--;
  317.     cond = sstack[ssp].s_cond;
  318.     loading = sstack[ssp].s_loading;
  319.     input = sstack[ssp].s_file;
  320.     if (ssp == 0)
  321.         sourcing = loading;
  322.     return(0);
  323. }
  324.  
  325. /*
  326.  * Touch the indicated file.
  327.  * This is nifty for the shell.
  328.  */
  329. alter(name)
  330.     char name[];
  331. {
  332.     struct stat statb;
  333.     long time();
  334.     struct timeval tvp[2];
  335.  
  336.     if (stat(name, &statb) < 0)
  337.         return;
  338.     /*
  339.      * With a distributed file system we can't count on our time()
  340.      * being the same as the server's, so we just set the access
  341.      * time to be greater than the modify time.  The old code
  342.      * used to set the access time to one second greater than time(),
  343.      * which still might be less than the server's modify time.
  344.      */
  345.     tvp[0].tv_sec = (long) statb.st_mtime + 1;
  346.     tvp[0].tv_usec = 0;
  347.     tvp[1].tv_sec = (long) statb.st_mtime;
  348.     tvp[1].tv_usec = 0;
  349.     utimes(name, tvp);
  350. }
  351.  
  352. /*
  353.  * Examine the passed line buffer and
  354.  * return true if it is all blanks and tabs.
  355.  */
  356. blankline(linebuf)
  357.     char linebuf[];
  358. {
  359.     register char *cp;
  360.  
  361.     for (cp = linebuf; *cp; cp++)
  362.         if (*cp != ' ' && *cp != '\t')
  363.             return(0);
  364.     return(1);
  365. }
  366.  
  367. /*
  368.  * Get sender's name from this message.  If the message has
  369.  * a bunch of arpanet stuff in it, we may have to skin the name
  370.  * before returning it.
  371.  */
  372. char *
  373. nameof(mp, reptype)
  374.     register struct message *mp;
  375. {
  376.     register char *cp, *cp2;
  377.  
  378.     cp = skin(name1(mp, reptype));
  379.     if (reptype != 0 || charcount(cp, '!') < 2)
  380.         return(cp);
  381.     cp2 = rindex(cp, '!');
  382.     cp2--;
  383.     while (cp2 > cp && *cp2 != '!')
  384.         cp2--;
  385.     if (*cp2 == '!')
  386.         return(cp2 + 1);
  387.     return(cp);
  388. }
  389.  
  390. /*
  391.  * Skin an arpa net address according to the RFC 822 interpretation
  392.  * of "host-phrase."
  393.  */
  394. char *
  395. skin(name)
  396.     char *name;
  397. {
  398.     register int c;
  399.     register char *cp, *cp2;
  400.     char *bufend;
  401.     int gotlt, lastsp;
  402.     char nbuf[BUFSIZ];
  403.     int nesting;
  404.  
  405.     if (name == NOSTR)
  406.         return(NOSTR);
  407.     if (index(name, '(') == NOSTR && index(name, '<') == NOSTR
  408.         && index(name, ' ') == NOSTR)
  409.         return(name);
  410.     gotlt = 0;
  411.     lastsp = 0;
  412.     bufend = nbuf;
  413.     for (cp = name, cp2 = bufend; c = *cp++; ) {
  414.         switch (c) {
  415.         case '(':
  416.             /*
  417.              * Start of a "comment".
  418.              * Ignore it.
  419.              */
  420.             nesting = 1;
  421.             while ((c = *cp) != 0) {
  422.                 cp++;
  423.                 switch (c) {
  424.                 case '\\':
  425.                     if (*cp == 0)
  426.                         goto outcm;
  427.                     cp++;
  428.                     break;
  429.                 case '(':
  430.                     nesting++;
  431.                     break;
  432.  
  433.                 case ')':
  434.                     --nesting;
  435.                     break;
  436.                 }
  437.  
  438.                 if (nesting <= 0)
  439.                     break;
  440.             }
  441.         outcm:
  442.             lastsp = 0;
  443.             break;
  444.  
  445.         case '"':
  446.             /*
  447.              * Start of a "quoted-string".
  448.              * Copy it in its entirety.
  449.              */
  450.             while ((c = *cp) != 0) {
  451.                 cp++;
  452.                 switch (c) {
  453.                 case '\\':
  454.                     if ((c = *cp) == 0)
  455.                         goto outqs;
  456.                     cp++;
  457.                     break;
  458.                 case '"':
  459.                     goto outqs;
  460.                 }
  461.                 *cp2++ = c;
  462.             }
  463.         outqs:
  464.             lastsp = 0;
  465.             break;
  466.  
  467.         case ' ':
  468.             if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
  469.                 cp += 3, *cp2++ = '@@';
  470.             else
  471.             if (cp[0] == '@@' && cp[1] == ' ')
  472.                 cp += 2, *cp2++ = '@@';
  473.             else
  474.                 lastsp = 1;
  475.             break;
  476.  
  477.         case '<':
  478.             cp2 = bufend;
  479.             gotlt++;
  480.             lastsp = 0;
  481.             break;
  482.  
  483.         case '>':
  484.             if (gotlt) {
  485.                 gotlt = 0;
  486.                 while (*cp != ',' && *cp != 0)
  487.                     cp++;
  488.                 if (*cp == 0 )
  489.                     goto done;
  490.                 *cp2++ = ',';
  491.                 *cp2++ = ' ';
  492.                 bufend = cp2;
  493.                 break;
  494.             }
  495.  
  496.             /* Fall into . . . */
  497.  
  498.         default:
  499.             if (lastsp) {
  500.                 lastsp = 0;
  501.                 *cp2++ = ' ';
  502.             }
  503.             *cp2++ = c;
  504.             break;
  505.         }
  506.     }
  507. done:
  508.     *cp2 = 0;
  509.  
  510.     return(savestr(nbuf));
  511. }
  512.  
  513. /*
  514.  * Fetch the sender's name from the passed message.
  515.  * Reptype can be
  516.  *    0 -- get sender's name for display purposes
  517.  *    1 -- get sender's name for reply
  518.  *    2 -- get sender's name for Reply
  519.  */
  520. char *
  521. name1(mp, reptype)
  522.     register struct message *mp;
  523. {
  524.     char namebuf[LINESIZE];
  525.     char linebuf[LINESIZE];
  526.     register char *cp, *cp2;
  527.     register FILE *ibuf;
  528.     int first = 1;
  529.  
  530.     if ((cp = hfield("from", mp)) != NOSTR)
  531.         return cp;
  532.     if (reptype == 0 && (cp = hfield("sender", mp)) != NOSTR)
  533.         return cp;
  534.     ibuf = setinput(mp);
  535.     namebuf[0] = 0;
  536.     if (readline(ibuf, linebuf, LINESIZE) < 0)
  537.         return(savestr(namebuf));
  538. newname:
  539.     for (cp = linebuf; *cp && *cp != ' '; cp++)
  540.         ;
  541.     for (; *cp == ' ' || *cp == '\t'; cp++)
  542.         ;
  543.     for (cp2 = &namebuf[strlen(namebuf)];
  544.          *cp && *cp != ' ' && *cp != '\t' && cp2 < namebuf + LINESIZE - 1;)
  545.         *cp2++ = *cp++;
  546.     *cp2 = '\0';
  547.     if (readline(ibuf, linebuf, LINESIZE) < 0)
  548.         return(savestr(namebuf));
  549.     if ((cp = index(linebuf, 'F')) == NULL)
  550.         return(savestr(namebuf));
  551.     if (strncmp(cp, "From", 4) != 0)
  552.         return(savestr(namebuf));
  553.     while ((cp = index(cp, 'r')) != NULL) {
  554.         if (strncmp(cp, "remote", 6) == 0) {
  555.             if ((cp = index(cp, 'f')) == NULL)
  556.                 break;
  557.             if (strncmp(cp, "from", 4) != 0)
  558.                 break;
  559.             if ((cp = index(cp, ' ')) == NULL)
  560.                 break;
  561.             cp++;
  562.             if (first) {
  563.                 strcpy(namebuf, cp);
  564.                 first = 0;
  565.             } else
  566.                 strcpy(rindex(namebuf, '!')+1, cp);
  567.             strcat(namebuf, "!");
  568.             goto newname;
  569.         }
  570.         cp++;
  571.     }
  572.     return(savestr(namebuf));
  573. }
  574.  
  575. /*
  576.  * Count the occurances of c in str
  577.  */
  578. charcount(str, c)
  579.     char *str;
  580. {
  581.     register char *cp;
  582.     register int i;
  583.  
  584.     for (i = 0, cp = str; *cp; cp++)
  585.         if (*cp == c)
  586.             i++;
  587.     return(i);
  588. }
  589.  
  590. /*
  591.  * Are any of the characters in the two strings the same?
  592.  */
  593. anyof(s1, s2)
  594.     register char *s1, *s2;
  595. {
  596.  
  597.     while (*s1)
  598.         if (index(s2, *s1++))
  599.             return 1;
  600.     return 0;
  601. }
  602.  
  603. /*
  604.  * Convert c to upper case
  605.  */
  606. raise(c)
  607.     register c;
  608. {
  609.  
  610.     if (islower(c))
  611.         return toupper(c);
  612.     return c;
  613. }
  614.  
  615. /*
  616.  * Copy s1 to s2, return pointer to null in s2.
  617.  */
  618. char *
  619. copy(s1, s2)
  620.     register char *s1, *s2;
  621. {
  622.  
  623.     while (*s2++ = *s1++)
  624.         ;
  625.     return s2 - 1;
  626. }
  627.  
  628. /*
  629.  * See if the given header field is supposed to be ignored.
  630.  */
  631. isign(field, ignore)
  632.     char *field;
  633.     struct ignoretab ignore[2];
  634. {
  635.     char realfld[BUFSIZ];
  636.  
  637.     if (ignore == ignoreall)
  638.         return 1;
  639.     /*
  640.      * Lower-case the string, so that "Status" and "status"
  641.      * will hash to the same place.
  642.      */
  643.     istrcpy(realfld, field);
  644.     if (ignore[1].i_count > 0)
  645.         return (!member(realfld, ignore + 1));
  646.     else
  647.         return (member(realfld, ignore));
  648. }
  649.  
  650. member(realfield, table)
  651.     register char *realfield;
  652.     struct ignoretab *table;
  653. {
  654.     register struct ignore *igp;
  655.  
  656.     for (igp = table->i_head[hash(realfield)]; igp != 0; igp = igp->i_link)
  657.         if (*igp->i_field == *realfield &&
  658.             equal(igp->i_field, realfield))
  659.             return (1);
  660.     return (0);
  661. }
  662. @
  663.  
  664.  
  665. 1.1
  666. log
  667. @Initial revision
  668. @
  669. text
  670. @d24 1
  671. d306 1
  672. a306 1
  673.     time_t time_p[2];
  674. d310 12
  675. a321 3
  676.     time_p[0] = time((long *) 0) + 1;
  677.     time_p[1] = statb.st_mtime;
  678.     utime(name, time_p);
  679. @
  680.